package Scene;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;

import javax.swing.JOptionPane;

import org.jbox2d.collision.AABB;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.World;
import org.mt4j.MTApplication;
import org.mt4j.components.MTComponent;
import org.mt4j.components.visibleComponents.font.FontManager;
import org.mt4j.components.visibleComponents.shapes.MTRectangle;
import org.mt4j.components.visibleComponents.shapes.MTRectangle.PositionAnchor;
import org.mt4j.components.visibleComponents.widgets.MTTextArea;
import org.mt4j.input.inputProcessors.globalProcessors.CursorTracer;
import org.mt4j.sceneManagement.AbstractScene;
import org.mt4j.sceneManagement.Iscene;
import org.mt4j.util.MTColor;
import org.mt4j.util.math.Vector3D;

import processing.core.PGraphics;
import util.PhysicsHelper;

import Controller.Player;
import GameObjects.GameBall;
import GameObjects.GameBrick;
import GameObjects.PlayerBrick;
import Level.Maploader;
import advanced.physics.physicsShapes.PhysicsRectangle;
import advanced.physics.util.UpdatePhysicsAction;

public class FingerBreakScene extends AbstractScene {
	private float timeStep = 1.0f / 60.0f;
	private int constraintIterations = 10;
	
	/** THE CANVAS SCALE **/
	private float scale = 105;
	private MTApplication app;
	private World world;
	private short brickcount;
	private Iscene endGame;
	
	private MTComponent physicsContainer;
	private ArrayList<GameBall> balls;
	private Player player1, player2;
	private MTTextArea infoFieldPlayerOne, infoFieldPlayerTwo;
	
	public FingerBreakScene(MTApplication mtApplication, String name) {
		super(mtApplication, name);
		this.app = mtApplication;
		
		createWorld();
		
		this.registerGlobalInputProcessor(new CursorTracer(app, this));
		
		//Update the positions of the components according the the physics simulation each frame
		this.registerPreDrawAction(new UpdatePhysicsAction(world, timeStep, constraintIterations, scale));
		
		physicsContainer = new MTComponent(app);
		//Scale the physics container. Physics calculations work best when the dimensions are small (about 0.1 - 10 units)
		//So we make the display of the container bigger and add in turn make our physics object smaller
		physicsContainer.scale(scale, scale, 1, Vector3D.ZERO_VECTOR);
		this.getCanvas().addChild(physicsContainer);
		
		//Create borders around the screen
		this.createScreenBorders(physicsContainer);
		
		
		
		//Create the textfield for the score and live
		infoFieldPlayerOne = new MTTextArea(mtApplication, FontManager.getInstance().createFont(app, "arial.ttf", 
				100, new MTColor(0, 0, 255, 100), new MTColor(0, 0, 0, 0))); 
		infoFieldPlayerOne.setAnchor(PositionAnchor.CENTER);
		infoFieldPlayerOne.setNoFill(true);
		infoFieldPlayerOne.setNoStroke(true);
		infoFieldPlayerOne.rotateZGlobal(infoFieldPlayerOne.getCenterPointLocal(), 90f);
		infoFieldPlayerOne.unregisterAllInputProcessors();
		this.getCanvas().addChild(infoFieldPlayerOne);
		infoFieldPlayerOne.setPositionGlobal(new Vector3D(app.getWidth()/8, app.getHeight()/2));
		
		infoFieldPlayerTwo = new MTTextArea(mtApplication, FontManager.getInstance().createFont(app, "arial.ttf", 
				100, new MTColor(255,0, 0, 100), new MTColor(0, 0, 0, 0))); 
		infoFieldPlayerTwo.setAnchor(PositionAnchor.CENTER);
		infoFieldPlayerTwo.setNoFill(true);
		infoFieldPlayerTwo.setNoStroke(true);
		infoFieldPlayerTwo.rotateZGlobal(infoFieldPlayerTwo.getCenterPointLocal(), -90f);
		infoFieldPlayerTwo.unregisterAllInputProcessors();
		this.getCanvas().addChild(infoFieldPlayerTwo);
		infoFieldPlayerTwo.setPositionGlobal(new Vector3D(app.getWidth()/8*7, app.getHeight()/2));
		
		
		player1 = new Player(app.getWidth()/4, app.getHeight(), MTColor.BLUE, app, physicsContainer, world, scale);
		player1.setPositionGlobal(new Vector3D(app.getWidth()/8, app.getHeight()/2));
		player1.setName("Blau");
		this.getCanvas().addChild(player1);
		
		player2 = new Player(app.getWidth()/4, app.getHeight(), MTColor.RED, app, physicsContainer, world, scale);
		player2.setPositionGlobal(new Vector3D(app.getWidth()/8*7, app.getHeight()/2));
		player2.setName("Rot");
		this.getCanvas().addChild(player2);
		
		
		balls = new ArrayList<GameBall>();
		createBall(player1);
		createBall(player2);
				
		try {
			brickcount = Maploader.loadMap("level1.txt", app, world, physicsContainer, scale);
		} catch (IOException e) {
			JOptionPane.showMessageDialog(app, "Couldn't load Map", "Error", JOptionPane.ERROR_MESSAGE);
		}
	}

	@Override
	public void init() {}

	@Override
	public void shutDown() {}	
	
	/**
	 * Method which is overrides to use polling about the relation state.
	 */
	public void drawAndUpdate(PGraphics graphics, long timeDelta) {
		super.drawAndUpdate(graphics, timeDelta);				
		
		for(GameBall _ball : balls){
			_ball.handleVelocity(7.0f);
		}
		checkCollide();
		checkBallOutsiteLevel();
		updateScore();
		
		if(brickcount <= 0){
			// TODO wechsel zur mainscene oder irgendwie spiel einfrieren damit man den entpunktestand sieht
			
			if(player1.getScore() > player2.getScore()){
				endGame = new EndGameScene(app, "Finger Break Scene", 1, player1.getScore());
				app.addScene(endGame);
			} else if(player1.getScore() == player2.getScore()){
				endGame = new EndGameScene(app, "Finger Break Scene", 0, player2.getScore());
				app.addScene(endGame);
			} else {
				endGame = new EndGameScene(app, "Finger Break Scene", 2, player2.getScore());
				app.addScene(endGame);
			}
			
			app.changeScene(endGame);
		}
		
//		PhysicsHelper.drawDebugPhysics(app, world, scale); //For debug drawing!		
	}
	
	private void updateScore() {
		//System.out.println("Update!");
		infoFieldPlayerOne.setText(""+player1.getScore());
		infoFieldPlayerOne.setPositionGlobal(new Vector3D(app.getWidth()/8, app.getHeight()/2));
		infoFieldPlayerTwo.setText(""+player2.getScore());
		infoFieldPlayerTwo.setPositionGlobal(new Vector3D(app.getWidth()/8*7, app.getHeight()/2));

	}
	
	public void checkBallOutsiteLevel(){
		for(GameBall _ball : (ArrayList<GameBall>)balls.clone()){
			if(_ball.getCenterPointGlobal().getX() < -15){
				balls.remove(_ball);
				_ball.destroy();
				createBall(player1);
				player1.addScore(-20);
			}else if(_ball.getCenterPointGlobal().getX() > app.width+15){
				balls.remove(_ball);
				_ball.destroy();
				createBall(player2);
				player2.addScore(-20);
			}
		}
		
	}

	public void checkCollide(){
		Set<Body> collidedObjectList;
		for(GameBall _ball : balls){
			if(!(collidedObjectList = _ball.getBody().getBodiesInContact()).isEmpty()){
				for(Body collided : collidedObjectList){
					Object collidedObject = collided.getUserData();
					
					//Ball colides with a PlayerBrick, set the affinity to the colided player
					if(collidedObject.getClass().equals(PlayerBrick.class)){
						_ball.setPlayerAffinity(((PlayerBrick)collidedObject).getPlayerAffinity());
						_ball.setFillColor(((PlayerBrick)collidedObject).getPlayerAffinity().getPlayerColor());
					}

					//Ball colides with a GameBrick
					if(collidedObject.getClass().equals(GameBrick.class)){
						_ball.getPlayerAffinity().addScore(10);
						
						
						
						if(((GameBrick)collidedObject).decreaseStrenght() <= 0){
							((GameBrick)collidedObject).destroy();
							brickcount--;
						}
					}
				}
			}
		}
	}
	
	public void createBall(Player _player){
		GameBall ball = new GameBall(app, _player.getCenterPointGlobal(), 5, world, scale);
		ball.setFillColor(_player.getPlayerColor());
		ball.setPlayerAffinity(_player);
		physicsContainer.addChild(ball);
		balls.add(ball);
	}
	
	private void createWorld(){
		float worldOffset = 10; //Make Physics world slightly bigger than screen borders
		//Physics world dimensions
		AABB worldAABB = new AABB(new Vec2(-worldOffset, -worldOffset), new Vec2((app.width)/scale + worldOffset, (app.height)/scale + worldOffset));
		Vec2 gravity = new Vec2(0, 0);
		boolean sleep = true;
		
		//Create the pyhsics world
		this.world = new World(worldAABB, gravity, sleep);
	}
	
	private void createScreenBorders(MTComponent parent){
		//Top border
		float borderWidth = app.width;
		float borderHeight = 50f;
		Vector3D pos = new Vector3D(app.width/2, -(borderHeight/2));
		PhysicsRectangle borderTop = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
		borderTop.setFillColor(MTColor.WHITE);
		borderTop.setName("borderTop");
		parent.addChild(borderTop);
		//Bottom border
		pos = new Vector3D(app.width/2 , app.height + (borderHeight/2));
		PhysicsRectangle borderBottom = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0,0,0, scale);
		borderBottom.setFillColor(MTColor.WHITE);
		borderBottom.setName("borderBottom");
		parent.addChild(borderBottom);
//		// Left border
//		borderWidth = 50f;
//		borderHeight = app.height;
//		pos = new Vector3D(-(borderWidth / 2f), app.height / 2f);
//		PhysicsRectangle borderLeft = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0, 0, 0, scale);
//		borderLeft.setName("borderLeft");
//		parent.addChild(borderLeft);
//		// Right border
//		pos = new Vector3D(app.width + (borderWidth / 2), app.height / 2);
//		PhysicsRectangle borderRight = new PhysicsRectangle(pos, borderWidth, borderHeight, app, world, 0, 0, 0, scale);
//		borderRight.setName("borderRight");
//		parent.addChild(borderRight);
	}

}
